# -*- coding: utf-8 -*-
"""
    xfree.core.user.update
    ~~~~~~~~~~~~~~~~~~~~~
    文件描述：本模块提供了在xfree中更新用户详情时使用的服务。
    作者：xfree
    邮箱：cy_83k@qq.com

"""

from abc import ABC, abstractmethod

import attr

from ..changesets import empty, is_empty


def _should_assign(current, new):
    """
    辅助函数，用于判断是否应该将新值赋给用户属性。
    如果新值不为空且与当前值不同，则返回True。
    """
    return not is_empty(new) and current != new


@attr.s(hash=True, eq=True, order=True, repr=True, frozen=True)
class UserDetailsChange(object):
    """
    表示用户详情变更的对象。
    """

    birthday = attr.ib(default=empty)  # 生日
    gender = attr.ib(default=empty)     # 性别
    location = attr.ib(default=empty)   # 位置
    website = attr.ib(default=empty)    # 网站
    avatar = attr.ib(default=empty)     # 头像
    signature = attr.ib(default=empty)  # 签名
    notes = attr.ib(default=empty)      # 备注

    def assign_to_user(self, user):
        """
        将变更应用到用户对象上。
        遍历所有属性，如果新值不为空且与当前值不同，则更新用户属性。
        """
        for name, value in attr.asdict(self).items():
            if _should_assign(getattr(user, name), value):
                setattr(user, name, value)


@attr.s(hash=True, eq=True, order=True, repr=False, frozen=True)
class PasswordUpdate(object):
    """
    表示用户密码更新的对象。
    """

    old_password = attr.ib()  # 旧密码
    new_password = attr.ib()  # 新密码


@attr.s(hash=True, eq=True, order=True, repr=True, frozen=True)
class EmailUpdate(object):
    """
    表示用户电子邮件地址变更的对象。
    """

    # TODO(anr): 一旦Python2被淘汰，就改为str.lower
    old_email = attr.ib(converter=lambda x: x.lower())  # 旧电子邮件
    new_email = attr.ib(converter=lambda x: x.lower())  # 新电子邮件


@attr.s(hash=True, eq=True, order=True, repr=True, frozen=True)
class SettingsUpdate(object):
    """
    表示用户设置更新的对象。
    """

    language = attr.ib()  # 语言设置
    theme = attr.ib()     # 主题设置

    def assign_to_user(self, user):
        """
        将变更应用到用户对象上。
        遍历所有属性，如果新值不为空且与当前值不同，则更新用户属性。
        """
        for name, value in attr.asdict(self).items():
            if _should_assign(getattr(user, name), value):
                setattr(user, name, value)


class UserSettingsUpdatePostProcessor(ABC):
    """
    用于响应用户更新设置的接口。
    此后处理器接收更新了设置的用户对象和应用的变更集。
    此后处理器在更新持久化后被调用，因此任何进一步的变更必须单独持久化。
    """

    @abstractmethod
    def post_process_settings_update(self, user, settings_update):
        """
        此方法是抽象的，子类必须实现。
        """
        pass